﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

using Storm.TextEditor.Parser.XML;

namespace Storm.TextEditor.Languages
{
    /// <summary>
    /// Represents a loader for all languages defined via Xml and in *.lang files.
    /// </summary>
    public sealed class LanguageLoader
    {
        #region Fields

        private static string dialogFilter = "";
        private static string xmlLanguageFileExtension = ".lang";

        private static LanguageList languageList = null;
        private static Hashtable foundLanguages = new Hashtable();

        #endregion

        #region Properties

        /// <summary>
        /// Gets the dialog filter of all the languages combined.
        /// </summary>
        /// <value>The dialog filter.</value>
        public static string DialogFilter
        {
            get { return dialogFilter; }
            internal set { dialogFilter = value; }
        }

        /// <summary>
        /// Gets the file extension of a file that defines a language for the TextEditor to use.
        /// </summary>
        public static string XmlLanguageFileExtension
        {
            get { return xmlLanguageFileExtension; }
        }

        /// <summary>
        /// Gets the list of languages that a LanguageLoader can load.
        /// </summary>
        public static LanguageList LanguageList
        {
            get
            {
                if (languageList == null)
                {
                    languageList = new LanguageList();
                    XmlLanguage[] languages = (XmlLanguage[])Enum.GetValues(typeof(XmlLanguage));

                    foreach (XmlLanguage currentLanguage in languages)
                    {
                        if (currentLanguage != XmlLanguage.None && currentLanguage != XmlLanguage.Unknown)
                        {
                            Stream fileStream = GetSyntaxStream(GetSyntaxFileName(currentLanguage));
                            languageList.Add(Language.FromSyntaxFile(fileStream));
                        }
                    }
                }

                return languageList;
            }
        }

        /// <summary>
        /// Gets or sets the found languages.
        /// </summary>
        /// <value>The found languages.</value>
        public static Hashtable FoundLanguages
        {
            get { return foundLanguages; }
            internal set { foundLanguages = value; }
        }

        #endregion

        #region Methods

        #region Public

        /// <summary>
        /// Sets the language of a TextEditor to the specified XmlLanguage.
        /// </summary>
        /// <param name="editor">TextEditor to set language for.</param>
        /// <param name="language">New XmlLanguage for the specified TextEditor.</param>
        public static void SetSyntax(TextEditor editor, XmlLanguage language)
        {
            Stream fileStream = GetSyntaxStream(GetSyntaxFileName(language));
            editor.Document.Parser.Init(Language.FromSyntaxFile(fileStream));

            fileStream.Close();
        }

        /// <summary>
        /// Sets the language of a TextEditor to the specified file.
        /// </summary>
        /// <param name="editor">TextEditor to set language for.</param>
        /// <param name="filePath">New XmlLanguage defition file for the specified TextEditor.</param>
        public static void SetSyntax(TextEditor editor, string filePath)
        {
            editor.Document.Parser.Init(LanguageLoader.LanguageList.GetLanguageFromFile(filePath));
        }

        /// <summary>
        /// Returns a Language from the given XmlLanguage.
        /// </summary>
        /// <param name="language">XmlLanguage to generate a Language for.</param>
        public static Language GetLanguageFrom(XmlLanguage language)
        {
            Stream fileStream = GetSyntaxStream(GetSyntaxFileName(language));
            return Language.FromSyntaxFile(fileStream);
        }

        #endregion

        #region Private

        /// <summary>
        /// Returns a Stream for the specified path.
        /// </summary>
        /// <param name="filePath">Path to create a Stream for.</param>
        private static Stream GetSyntaxStream(string filePath)
        {
            Stream fileStream = typeof(LanguageLoader).Assembly.GetManifestResourceStream(filePath);
            return fileStream;
        }

        #endregion

        #region Internal

        /// <summary>
        /// Returns the path to the *.lang file defining the given XmlLanguage.
        /// </summary>
        /// <param name="language">XmlLanguage to find path for.</param>
        internal static string GetSyntaxFileName(XmlLanguage language)
        {
            if (language == XmlLanguage.None || language == XmlLanguage.Unknown)
                return "Storm.TextEditor.Languages.Text.lang";

            string filePath = Enum.GetName(typeof(XmlLanguage), language);
            filePath += xmlLanguageFileExtension;

            return "Storm.TextEditor.Languages." + filePath;
        }

        #endregion

        #endregion

        /// <summary>
        /// Initializes a new instance of LanguageLoader.
        /// </summary>
        public LanguageLoader()
        {
        }
    }
}
